
#include <Arduino.h>
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <freertos/FreeRTOS.h>  
#include <freertos/task.h>

#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif

hw_timer_t * timer = NULL;
const int Timeout = 50;//ms
TFT_eSPI tft = TFT_eSPI(135,240); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];

void Task1( void *pvParameters );//
void Task2( void *pvParameters );//图片1

#if USE_LV_LOG != 0
/* Serial debugging */
void my_print(lv_log_level_t level, const char * file, uint32_t line, const char * dsc)
{

    Serial.printf("%s@%d->%s\r\n", file, line, dsc);
    Serial.flush();
}
#endif

/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);

    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);
    tft.pushColors(&color_p->full, w * h, true);
    tft.endWrite();

    lv_disp_flush_ready(disp);
}

/* Reading input device (simulated encoder here) */
bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data)
{
    static int32_t last_diff = 0;
    int32_t diff = 0; /* Dummy - no movement */
    int btn_state = LV_INDEV_STATE_REL; /* Dummy - no press */

    data->enc_diff = diff - last_diff;;
    data->state = btn_state;

    last_diff = diff;

    return false;
}
void IRAM_ATTR onTimer()
{
  lv_task_handler(); /* LVGL 工作函数 */
}

void setup()
{

    Serial.begin(115200); /* prepare for possible serial debug */
    lv_init();
   timer = timerBegin(0, 80, true);//开启定时器 选择timer0，分频系数为80，向上计数
   timerAttachInterrupt(timer, &onTimer, true);//开启定时器中断函数
   timerAlarmWrite(timer, Timeout * 1000, true);//  保护值  开启自动重载
   timerAlarmEnable(timer);//使能定时器
#if USE_LV_LOG != 0
    lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif

    //tft.init();
    tft.begin(); /* TFT init */
    tft.setRotation(1); /* Landscape orientation */
    tft.fillScreen(TFT_WHITE);
    tft.setTextSize(2);
    tft.setCursor(0, 0);
    tft.setTextDatum(MC_DATUM);
    void lv_style_init(void);
    
    lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

    /*Initialize the display*/
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = 240;
    disp_drv.ver_res = 135;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    /*Initialize the (dummy) input device driver*/
    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_ENCODER;
    indev_drv.read_cb = read_encoder;
    lv_indev_drv_register(&indev_drv);

    xTaskCreatePinnedToCore(
    Task1     //任务函数
    ,  "Task1"   /* 任务名字 没啥用，就是描述*/
    ,  1024   /*堆栈大小，单位为字节*/
    ,  NULL  /*作为任务输入传递的参数*/
    ,  1  // /*任务的优先级*/Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL 
    ,  ARDUINO_RUNNING_CORE); //指定运行任务的CPU

  xTaskCreatePinnedToCore(
    Task2
    ,  "Task2"
    ,  1024  // Stack size
    ,  NULL
    ,  2  // Priority
    ,  NULL 
    ,  ARDUINO_RUNNING_CORE);//
}


void loop()
{
  ;
}

/*---------------------- Tasks ---------------------*/

void Task1(void *pvParameters)  // This is a task.
{
  tft.fillScreen(TFT_WHITE);
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    
  }
}
void Task2(void *pvParameters)  // This is a task.
{
  
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    tft.fillScreen(TFT_WHITE);
    /* 引入图片,相当于extern */
    LV_IMG_DECLARE(cat);
    lv_obj_t *image1 = lv_img_create(lv_scr_act(),NULL);/* 创建image 控件*/
    lv_img_set_src(image1,&cat); /* 为控件设置图片*/
    lv_obj_align(image1,NULL,LV_ALIGN_IN_TOP_MID,0,0);/* 设置控件的对齐方式,相对坐标*/
    vTaskDelay(1000);  // one tick delay (15ms) in between reads for stability
    tft.fillScreen(TFT_WHITE);

    LV_IMG_DECLARE(love);
    lv_img_set_src(image1,&love); /* 为控件设置图片*/
    lv_obj_align(image1,NULL,LV_ALIGN_IN_TOP_MID,0,0);/* 设置控件的对齐方式,相对坐标*/
    vTaskDelay(1000);  // one tick delay (15ms) in between reads for stability
    lv_obj_del(image1);
    tft.fillScreen(TFT_WHITE);

    lv_obj_t *scr = lv_disp_get_scr_act(NULL); /* 获取当前屏幕 */

    lv_obj_t *label1 = lv_label_create(scr,NULL); /* 创建 label 控件 */
    lv_label_set_recolor(label1, true); /* 允许文字重新着色 */
    lv_label_set_text(label1,"#000080 Moonbeam ##6666ff Moonbeam "); /* 设置文字 空格一定要有 */
    lv_obj_align(label1,NULL,LV_ALIGN_IN_TOP_MID,0,0); /* 设置位置 */
    vTaskDelay(1000); 
    lv_obj_del(label1);
    tft.fillScreen(TFT_WHITE);

    lv_obj_t *label2 = lv_label_create(scr,NULL); /* 创建 label 控件 */
    lv_label_set_text(label2,"abcdefghijklmnopqrstabsjdjnvjjchchccbc,"); /* 设置长文本  不支持汉字 */
    lv_label_set_long_mode(label2,LV_LABEL_LONG_SROLL_CIRC); /* 设置长文本的模式为循环滚动显示 */
    lv_obj_set_width(label2, 240);
    //lv_obj_align(label2, NULL, LV_ALIGN_CENTER, 0, 10); /* 设置位置 */
    vTaskDelay(3000);
    lv_obj_del(label2);
    tft.fillScreen(TFT_WHITE);

    

    /* 引入字体,等同于 extern */
    LV_FONT_DECLARE(gb2312_puhui32);
    static lv_style_t style_cn; /* 定义新的样式,请注意使用 static 或者全局变量 */
    lv_style_init(&style_cn);
    lv_style_set_text_font(&style_cn, LV_STATE_DEFAULT, &gb2312_puhui32);
    //汉字显示
    lv_obj_t *label3 = lv_label_create(scr,NULL); /* 创建 label 控件 */
    //lv_obj_set_style(label3,&style_cn); /* 为控件设置新的 style */
    lv_obj_add_style(label3, LV_LABEL_PART_MAIN, &style_cn);
    lv_obj_set_pos(label3,0,0); /* 设置控件的坐标 */
    lv_label_set_text(label3,"小先生"); /* 设置文字 */
    lv_obj_align(label3,NULL,LV_ALIGN_IN_TOP_MID,0,100); /* 设置控件的对齐方式-相对坐标 */
    vTaskDelay(1000);
    lv_obj_del(label2);
    tft.fillScreen(TFT_WHITE);


    /*Create an array for the points of the line*/
    static lv_point_t line_points[] = { {5, 5}, {5, 70}, {70, 180}, {180, 60}, {240, 10} };

    /*Create style*/
    static lv_style_t style_line;
    lv_style_init(&style_line);
    lv_style_set_line_width(&style_line, LV_STATE_DEFAULT, 8);
    lv_style_set_line_color(&style_line, LV_STATE_DEFAULT, LV_COLOR_BLUE);
    lv_style_set_line_rounded(&style_line, LV_STATE_DEFAULT, true);

    /*Create a line and apply the new style*/
    lv_obj_t * line1;
    line1 = lv_line_create(lv_scr_act(), NULL);
    lv_line_set_points(line1, line_points, 5);     /*Set the points*/
    lv_obj_add_style(line1, LV_LINE_PART_MAIN, &style_line);     /*Set the points*/
    lv_obj_align(line1, NULL, LV_ALIGN_CENTER, 0, 0);
    vTaskDelay(3000);
    lv_obj_del(line1);
    tft.fillScreen(TFT_WHITE);


    /*Create a LED and switch it OFF*/
    lv_obj_t * led1  = lv_led_create(lv_scr_act(), NULL);
    lv_obj_align(led1, NULL, LV_ALIGN_CENTER, -80, 0);
    lv_led_off(led1);

    /*Copy the previous LED and set a brightness*/
    lv_obj_t * led2  = lv_led_create(lv_scr_act(), led1);
    lv_obj_align(led2, NULL, LV_ALIGN_CENTER, 0, 0);
    lv_led_set_bright(led2, 190);

    /*Copy the previous LED and switch it ON*/
    lv_obj_t * led3  = lv_led_create(lv_scr_act(), led1);
    lv_obj_align(led3, NULL, LV_ALIGN_CENTER, 80, 0);
    lv_led_on(led3);
    vTaskDelay(2000);
    lv_obj_del(led1);
    lv_obj_del(led2);
    lv_obj_del(led3);
  }
}




/*
 * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: CC0-1.0
 */

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lvgl.h"
#include "esp_lcd_panel_gc9a01.h"

static const char *TAG = "example";

// Using SPI2 in the example
#define LCD_HOST  SPI2_HOST

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define EXAMPLE_LCD_PIXEL_CLOCK_HZ     (20 * 1000 * 1000)
#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL  1
#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL
#define EXAMPLE_PIN_NUM_DATA0          19
#define EXAMPLE_PIN_NUM_PCLK           18
#define EXAMPLE_PIN_NUM_CS             4
#define EXAMPLE_PIN_NUM_DC             5
#define EXAMPLE_PIN_NUM_RST            3
#define EXAMPLE_PIN_NUM_BK_LIGHT       2

// The pixel number in horizontal and vertical
#define EXAMPLE_LCD_H_RES              240
#define EXAMPLE_LCD_V_RES              240
// Bit number used to represent command and parameter
#define EXAMPLE_LCD_CMD_BITS           8
#define EXAMPLE_LCD_PARAM_BITS         8

#define EXAMPLE_LVGL_TICK_PERIOD_MS    2

extern void example_lvgl_demo_ui(lv_obj_t *scr);

static bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx;
    lv_disp_flush_ready(disp_driver);
    return false;
}

static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
    esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;
    int offsetx1 = area->x1;
    int offsetx2 = area->x2;
    int offsety1 = area->y1;
    int offsety2 = area->y2;
    // copy a buffer's content to a specific area of the display
    esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
}

static void example_increase_lvgl_tick(void *arg)
{
    /* Tell LVGL how many milliseconds has elapsed */
    lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
}

void app_main(void)
{
    static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
    static lv_disp_drv_t disp_drv;      // contains callback functions

    ESP_LOGI(TAG, "Turn off LCD backlight");
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT
    };
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));

    ESP_LOGI(TAG, "Initialize SPI bus");
    spi_bus_config_t buscfg = {
        .sclk_io_num = EXAMPLE_PIN_NUM_PCLK,
        .mosi_io_num = EXAMPLE_PIN_NUM_DATA0,
        .miso_io_num = -1,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t),
    };
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));

    ESP_LOGI(TAG, "Install panel IO");
    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = EXAMPLE_PIN_NUM_DC,
        .cs_gpio_num = EXAMPLE_PIN_NUM_CS,
        .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
        .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
        .spi_mode = 0,
        .trans_queue_depth = 10,
        .on_color_trans_done = example_notify_lvgl_flush_ready,
        .user_ctx = &disp_drv,
    };
    // Attach the LCD to the SPI bus
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));

    ESP_LOGI(TAG, "Install GC9A01 panel driver");
    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,
        .color_space = ESP_LCD_COLOR_SPACE_BGR,
        .bits_per_pixel = 16,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(io_handle, &panel_config, &panel_handle));

    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
    ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));

    ESP_LOGI(TAG, "Turn on LCD backlight");
    gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    ESP_LOGI(TAG, "Initialize LVGL library");
    lv_init();
    // alloc draw buffers used by LVGL
    // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
    lv_color_t *buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);
    lv_color_t *buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf2);
    // initialize LVGL draw buffers
    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 20);

    ESP_LOGI(TAG, "Register display driver to LVGL");
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = EXAMPLE_LCD_H_RES;
    disp_drv.ver_res = EXAMPLE_LCD_V_RES;
    disp_drv.flush_cb = example_lvgl_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    disp_drv.user_data = panel_handle;
    lv_disp_t *disp = lv_disp_drv_register(&disp_drv);

    ESP_LOGI(TAG, "Install LVGL tick timer");
    // Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback = &example_increase_lvgl_tick,
        .name = "lvgl_tick"
    };
    esp_timer_handle_t lvgl_tick_timer = NULL;
    ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));

    ESP_LOGI(TAG, "Display LVGL Meter Widget");
    lv_obj_t *scr = lv_disp_get_scr_act(disp);
    example_lvgl_demo_ui(scr);

    while (1) {
        // raise the task priority of LVGL and/or reduce the handler period can improve the performance
        vTaskDelay(pdMS_TO_TICKS(10));
        // The task running lv_timer_handler should have lower priority than that running `lv_tick_inc`
        lv_timer_handler();
    }
}